﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ChessGame.Pieces;
using System.Drawing;
using System.Windows.Forms;
using System.Threading;
using ChessGame.Movement;
namespace ChessGame
{
    /// <summary>
    /// Set Object contains all the chesspieces of one side of the game
    /// </summary>
    public class Set
    {
        private Boolean colour; //True = Wit, False= Black;
        private List<Chesspiece> pieces;
        private static Chess form;
        private Game game;
        private Random randomizer;
        public Boolean firstMove = true;
        private Boolean isCheck;
        public String SideColour
        {
            get { if (colour) { return "White"; } else { return "Black"; } }
            set
            {
                if (value == "White") { colour = true; }
                else if (value == "Black") { colour = false; }
                else { throw new Exception("Only Black or White"); }
            }
        }
        public List<Chesspiece> Pieces
        {
            get { return pieces; }
            set { pieces = value; }
        }

        /// <summary>
        /// Set Constructor
        /// </summary>
        /// <param name="_form">The chessform to link the set</param>
        /// <param name="_game">The game to link set</param>
        /// <param name="colour">The colour of the game</param>
        public Set(Chess _form, Game _game, string colour)
        {
            form = _form;
            SideColour = colour;
            game = _game;
            // Creating the pieces;
            pieces = new List<Chesspiece>();
        }

        /// <summary>
        /// Start's the game
        /// </summary>
        public void Start()
        {
            CreatePieces();
            Make();
        }

        /// <summary>
        /// Stop's the game.
        /// </summary>
        public void Stop()
        {
            pieces.Clear();
            Make();
        }

        /// <summary>
        /// Moves a chesspiece to a certain place.
        /// </summary>
        /// <param name="startX">Chesspiece to move position X</param>
        /// <param name="startY">Chesspiece to move position Y</param>
        /// <param name="endX">Move to position X</param>
        /// <param name="endY">Move to position Y</param>
        public void Move(int startX, int startY, int endX, int endY)
        {
            Chesspiece basePiece = GetPiece(startX, startY);
            // Console.WriteLine(basePiece.BoardPosition);
            //Console.WriteLine(basePiece.positionX + " " + basePiece.positionY);
            form.ClearImage(SideColour, basePiece.Type, basePiece.BoardPosition);
            basePiece.SetPosition(endX, endY);
            basePiece.Turn();
            Thread.Sleep(20);
            //Console.WriteLine(endX+" "+endY);
            //Console.WriteLine(basePiece.positionX + " " + basePiece.positionY);
            form.SetImage(SideColour, basePiece.Type, basePiece.BoardPosition);
            form.ChangeSetColour(startX, startY, endX, endY);
            if (firstMove)
            {
                firstMove = false;
        }
        }

        /// <summary>
        /// Prints all pieces in console.
        /// </summary>
        public void PrintPieces()
        {
            foreach (Chesspiece chestpiece in pieces)
            {
                Console.WriteLine("Colour"+chestpiece.Colour+""+chestpiece.Type +" X:"+chestpiece.PositionX+" "+chestpiece.PositionY+"");
            }
        }

        /// <summary>
        /// Make the set in the form.
        /// </summary>
        public void Make()
        {
            foreach (Chesspiece chestpiece in pieces)
            {
                form.SetImage(SideColour, chestpiece.Type, chestpiece.BoardPosition);
            }

            //form.SetImage("White", "King", "E1");
        }

        /// <summary>
        /// Creates the default set.
        /// </summary>
        private void CreatePieces()
        {
            King king;
            Queen queen;
            Rook rook1;
            Rook rook2;
            Bishop bishop1;
            Bishop bishop2;
            Knight knight1;
            Knight knight2;
            Pawn pawn1;
            Pawn pawn2;
            Pawn pawn3;
            Pawn pawn4;
            Pawn pawn5;
            Pawn pawn6;
            Pawn pawn7;
            Pawn pawn8;
            // True = Wit, False= Black;
            // http://upload.wikimedia.org/wikipedia/commons/thumb/c/cd/Chess_l45.svg/26px-Chess_l45.svg.png
            if (colour)
            {

                king = new King(colour, 5, 1);
                queen = new Queen(colour, 4, 1);

                rook1 = new Rook(colour, 1, 1);
                rook2 = new Rook(colour, 8, 1);

                bishop1 = new Bishop(colour, 3, 1);
                bishop2 = new Bishop(colour, 6, 1);

                knight1 = new Knight(colour, 2, 1);
                knight2 = new Knight(colour, 7, 1);

                pawn1 = new Pawn(colour, 1, 2);
                pawn2 = new Pawn(colour, 2, 2);
                pawn3 = new Pawn(colour, 3, 2);
                pawn4 = new Pawn(colour, 4, 2);
                pawn5 = new Pawn(colour, 5, 2);
                pawn6 = new Pawn(colour, 6, 2);
                pawn7 = new Pawn(colour, 7, 2);
                pawn8 = new Pawn(colour, 8, 2);
            }
            else
            {
                king = new King(colour, 4, 8);
                queen = new Queen(colour, 5, 8);


                rook1 = new Rook(colour, 1, 8);
                rook2 = new Rook(colour, 8, 8);

                bishop1 = new Bishop(colour, 3, 8);
                bishop2 = new Bishop(colour, 6, 8);

                knight1 = new Knight(colour, 2, 8);
                knight2 = new Knight(colour, 7, 8);

                pawn1 = new Pawn(colour, 1, 7);
                pawn2 = new Pawn(colour, 2, 7);
                pawn3 = new Pawn(colour, 3, 7);
                pawn4 = new Pawn(colour, 4, 7);
                pawn5 = new Pawn(colour, 5, 7);
                pawn6 = new Pawn(colour, 6, 7);
                pawn7 = new Pawn(colour, 7, 7);
                pawn8 = new Pawn(colour, 8, 7);
            }
            pieces.Add(king);
            pieces.Add(queen);
            pieces.Add(rook1);
            pieces.Add(rook2);
            pieces.Add(bishop1);
            pieces.Add(bishop2);
            pieces.Add(knight1);
            pieces.Add(knight2);
            pieces.Add(pawn1);
            pieces.Add(pawn2);
            pieces.Add(pawn3);
            pieces.Add(pawn4);
            pieces.Add(pawn5);
            pieces.Add(pawn6);
            pieces.Add(pawn7);
            pieces.Add(pawn8);

        }

        /// <summary>
        /// Check if there's a piece on a certain position
        /// </summary>
        /// <param name="_x">Position X</param>
        /// <param name="_y">Position Y</param>
        /// <returns>if the there's a piece</returns>
        public bool CheckForPiece(int _x, int _y)
        {
            foreach (Chesspiece chestpiece in pieces)
            {
                if ((chestpiece.PositionX == _x) && (chestpiece.PositionY == _y))
                {
                    return true;
                }
            }
            return false;
        }

        /// <summary>
        /// Get's a piece on a certain position.
        /// </summary>
        /// <param name="_x">Position X</param>
        /// <param name="_y">Position Y</param>
        /// <returns>A Chesspiece object</returns>
        public Chesspiece GetPiece(int _x, int _y)
        {
            foreach (Chesspiece chestpiece in pieces)
            {
                if ((chestpiece.PositionX == _x) && (chestpiece.PositionY == _y))
                {
                    return chestpiece;
                }
            }
            throw new Exception("No ChestPiece");
        }

        /// <summary>
        /// Check if there's a chesspiece between certain coordination.
        /// </summary>
        /// <param name="baseObjectX">From position X</param>
        /// <param name="baseObjectY">From position Y</param>
        /// <param name="endPointX">To position X</param>
        /// <param name="endPointY">To position Y</param>
        /// <returns>True=Chesspiece between the coordinates</returns>
        public bool CheckIfBlocked(int baseObjectX, int baseObjectY, int endPointX, int endPointY)
        {
            try
            {
                Chesspiece chestpiece = GetPiece(baseObjectX, baseObjectY);
                switch (chestpiece.Type)
                {
                    case "Queen":
                        {
                            //return StraightLookup(baseObjectX, baseObjectY, endPointX, endPointY);
                            if ((baseObjectX - endPointX) == (baseObjectY - endPointY))
                            {
                                //Console.WriteLine("Diagonal: " + baseObjectX + " " + baseObjectY + " " + endPointX + " " + endPointY);
                                return DiagonalLookup(baseObjectX, baseObjectY, endPointX, endPointY);
                            }
                            else if ((-(baseObjectX - endPointX)) == (baseObjectY - endPointY))
                            {
                                //    Console.WriteLine("Diagonal: " + baseObjectX + " " + baseObjectY + " " + endPointX + " " + endPointY);
                                return DiagonalLookup(baseObjectX, baseObjectY, endPointX, endPointY);
                            }
                            else
                            {
                                //Console.WriteLine("Straight: " + baseObjectX + " " + baseObjectY + " " + endPointX + " " + endPointY);
                                return StraightLookup(baseObjectX, baseObjectY, endPointX, endPointY);
                            }
                        }
                    case "Bishop":
                        {
                            return DiagonalLookup(baseObjectX, baseObjectY, endPointX, endPointY);
                        }
                    case "Rook":
                        {
                            return StraightLookup(baseObjectX, baseObjectY, endPointX, endPointY);
                        }
                    default:
                        {
                            break;
                        }
                }

            }
            catch (Exception)
            {
                throw;
            }
            return false;
        }

        /// <summary>
        /// Gives a list of movement possibilities for the chesspiece on given coordinate.
        /// </summary>
        /// <param name="_x">Position X</param>
        /// <param name="_y">Position Y</param>
        /// <returns>List of MovementOption object</returns>
        public List<MovementOption> GetMovementPossiblities(int _x, int _y)
        {
            Chesspiece result;
            foreach (Chesspiece chestpiece in pieces)
            {
                if ((chestpiece.PositionX == _x) && (chestpiece.PositionY == _y))
                {
                    result = Transformer(chestpiece);
                    return result.GetMovementPossibilities();
                }

            }
            throw new Exception("No Piece here");
        }

        /// <summary>
        /// Gives a list of hit possibilities for the chesspiece on given coordinate.
        /// </summary>
        /// <param name="_x">Position X</param>
        /// <param name="_y">Position Y</param>
        /// <returns>List of HitOption object</returns>
        public List<HitOption> GetHitPossiblities(int _x, int _y)
        {
            Chesspiece result;
            foreach (Chesspiece chestpiece in pieces)
            {
                if ((chestpiece.PositionX == _x) && (chestpiece.PositionY == _y))
                {
                    result = Transformer(chestpiece);
                    return result.GetHitPossibilities();
                }

            }
            throw new Exception("No Piece here");
        }

        /// <summary>
        /// Transform the Chesspiece into his own baseclass.
        /// </summary>
        /// <param name="chestpiece">Chesspiece object</param>
        /// <returns>Base object</returns>
        public Chesspiece Transformer(Chesspiece chestpiece)
        {
            switch (chestpiece.Type)
            {
                case "Queen":
                    return (Queen)chestpiece;
                case "King":
                    return (King)chestpiece;
                case "Bishop":
                    return (Bishop)chestpiece;
                case "Knight":
                    return (Knight)chestpiece;
                case "Pawn":
                    return (Pawn)chestpiece;
                case "Rook":
                    return (Rook)chestpiece;
                default:
                    return chestpiece;
            }
        }

        /// <summary>
        /// Checks if there's a chesspiece between certain coordinates.
        /// </summary>
        /// <param name="baseObjectX">From position X</param>
        /// <param name="baseObjectY">From position Y</param>
        /// <param name="endPointX">To position X</param>
        /// <param name="endPointY">To position Y</param>
        /// <returns>Boolean if it's blocked or not</returns>
        public bool StraightLookup(int baseObjectX, int baseObjectY, int endPointX, int endPointY)
        {
            if (endPointX == baseObjectX)
            {
                //When base and endpoint are on the same vertical line x
                if (endPointY > baseObjectY)
                {
                    //When endpoint is higher as basepoint
                    for (int i = baseObjectY + 1; endPointY > i; i++)
                    {
                        if (game.CheckBothSidesForPieces(endPointX, i)) { return true; }
                    }
                }
                else
                {
                    //When endpoint is lower as basepoint
                    for (int i = baseObjectY - 1; endPointY < i; i--)
                    {
                        if (game.CheckBothSidesForPieces(endPointX, i)) { return true; }
                    }
                }
                return false;
            }
            else if (endPointY == baseObjectY)
            {
                //When base and endpoint are on the same horizontal line y
                if (endPointX > baseObjectX)
                {
                    for (int i = baseObjectX + 1; endPointX > i; i++)
                    {
                        //if (game.CheckOtherPieces(colour, i, endPointY)) { form.Hit(i, endPointY); }
                        if (game.CheckBothSidesForPieces(i, endPointY)) { return true; }
                    }

                    return false;
                }
                else
                {
                    //When endpoint is lower as basepoint
                    for (int i = baseObjectX - 1; endPointX < i; i--)
                    {
                        //if (game.CheckOtherPieces(colour, i, endPointY)) { form.Hit(i, endPointY); }
                        if (game.CheckBothSidesForPieces(i, endPointY)) { return true; }
                    }
                }
            }
            return false;
        }

        /// <summary>
        /// Checks if there's a chesspiece between certain coordinates.
        /// </summary>
        /// <param name="baseObjectX">From position X</param>
        /// <param name="baseObjectY">From position Y</param>
        /// <param name="endPointX">To position X</param>
        /// <param name="endPointY">To position Y</param>
        /// <returns>Boolean if it's blocked or not</returns>
        public bool DiagonalLookup(int baseObjectX, int baseObjectY, int endPointX, int endPointY)
        {
            int y, x;
            //if ((baseObjectX - endPointX) == (baseObjectY - endPointY))
            //{
            if (endPointY > baseObjectY)
            {
                // Y=Higher
                if (endPointX > baseObjectX)
                {
                    // X=Higher 
                    y = baseObjectY;
                    for (x = baseObjectX + 1; endPointX > x; x++)
                    {
                        y++;
                        if (game.CheckBothSidesForPieces(x, y)) { return true; }
                    }

                }
                else if (endPointX < baseObjectX)
                {
                    // X=Lower 
                    y = baseObjectY;
                    for (x = baseObjectX - 1; endPointX < x; x--)
                    {
                        y++;
                        if (game.CheckBothSidesForPieces(x, y)) { return true; }
                    }
                }
            }
            else
            {
                //Y=Lower
                if (endPointX > baseObjectX)
                {
                    //X==Higher
                    y = baseObjectY;
                    for (x = baseObjectX + 1; endPointX > x; x++)
                    {
                        y--;
                        if (game.CheckBothSidesForPieces(x, y)) { return true; }
                    }
                }
                else if (endPointX < baseObjectX)
                {
                    //X==Lower
                    y = baseObjectY;
                    for (x = baseObjectX - 1; endPointX < x; x--)
                    {
                        y--;
                        if (game.CheckBothSidesForPieces(x, y)) { return true; }
                    }
                }
            }
            return false;
        }

        /// <summary>
        /// Kill a certain chesspiece on given coordinate.
        /// </summary>
        /// <param name="inputX">Position X</param>
        /// <param name="inputY">Position Y</param>
        public void Kill(int inputX, int inputY)
        {
            Chesspiece basePiece = GetPiece(inputX, inputY);
            form.ClearImage(SideColour, basePiece.Type, basePiece.BoardPosition);
            pieces.Remove(basePiece);

        }

        /// <summary>
        /// Get's a random chesspiece
        /// </summary>
        /// <returns>Chesspiece object</returns>
        public Chesspiece RandomChesspiece()
        {
            randomizer = new Random();
            int random = randomizer.Next(0, pieces.Count);
            return pieces[random];
        }


        /// <summary>
        /// Get's a random chesspiece
        /// </summary>
        /// <returns>Chesspiece object</returns>
        public List<Chesspiece> GetAllChesspieces()
        {
            return pieces;
        }

        /// <summary>
        /// Get's a list of all chesspieces
        /// </summary>
        /// <returns>List of Chesspiece</returns>
        public List<Chesspiece> GetPieces()
        {
            return pieces;
        }

        /// <summary>
        /// Get the King
        /// </summary>
        /// <returns>King object</returns>
        public Chesspiece GetKing()
        {
            //return pieces.Where(c => c.Type == "King").ToList()[0];
            foreach (Chesspiece chesspiece in pieces)
            {
                if (chesspiece is King)
                {
                    return chesspiece;
                }
            }
            throw new Exception(" ");
        }
    }
}
